﻿/************************************************************************

 This file is part of "10 Second Tim".

 "10 Second Tim" is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 "10 Second Tim" is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with "10 Second Tim".  If not, see <http://www.gnu.org/licenses/>.

************************************************************************/

// All code (c)2013 Scott Bevin. all rights reserved

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LDE;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Media;

namespace LudumDare27
{
	public class Character
	{
		public enum Poses
		{
			Normal = 0,
			Dead = 1,

			Max,
		}

		public Sprite m_sprite;

		public Vector2 Position = Vector2.Zero;
		public Vector2 Velocity = Vector2.Zero;
		public Vector2 Acceleration = Vector2.Zero;

		public float Rotation = 0.0f;

		public ICharAnim CurrentAnim = null;

		private float slidetimer = 0.0f;

		public bool OnGround = false;
		public bool Jumping = false;
		public bool Sliding = false;
		public bool Dead = false;
		public bool DontFlip = false;

		public SoundEffect JumpSfx;
		public SoundEffect LandSfx;
		public SoundEffect FootstepSfx;
		public SoundEffect DiesSfx;

		public SoundEffect SlideSfx;
		private SoundEffectInstance SlideSfxInstance;

		public Character( Texture2D charsprite, ContentManager content )
		{
			m_sprite = new Sprite( charsprite, (int)Poses.Max );

			JumpSfx = content.Load<SoundEffect>( "Sfx/Jump" );
			LandSfx = content.Load<SoundEffect>( "Sfx/JumpLand" );
			FootstepSfx = content.Load<SoundEffect>( "Sfx/Footstep" );
			SlideSfx = content.Load<SoundEffect>( "Sfx/Slide" );
			DiesSfx = content.Load<SoundEffect>( "Sfx/TakeHit" );

			SlideSfxInstance = SlideSfx.CreateInstance( );
			SlideSfxInstance.IsLooped = true;
		}

		public void Jump( )
		{
			if ( OnGround && !Jumping )
			{
				Jumping = true;
				Velocity.Y = Defs.Game1.JumpVel;

				CurrentAnim = new JumpAnim( );

				JumpSfx.Play( );
			}
		}

		public void Slide( )
		{
			if ( OnGround && !Sliding )
			{
				slidetimer = Defs.Game1.Slidetime;
				Sliding = true;
				CurrentAnim = new Slideanim( );

				SlideSfxInstance.Play( );
			}
		}

		public void Kill( )
		{
			MediaPlayer.Stop( );

			if ( !Dead )
				DiesSfx.Play( );

			Dead = true;
			m_sprite.Frame = (int)Poses.Dead;
		}

		public void Update( float dt, float groundHeight, bool dontDoGround )
		{
			Velocity += Acceleration * dt;
			Position += Velocity * dt;

			if ( Math.Abs( Velocity.X ) <= float.Epsilon )
				slidetimer = -1.0f;

			if ( ( slidetimer -= dt ) < 0.0f )
			{
#if SILVERLIGHT
			SlideSfxInstance.Stop(  );
#else
				SlideSfxInstance.Stop( true );
#endif
				Sliding = false;
			}

			if ( Velocity.X > 0.0f || DontFlip )
				m_sprite.Effect = SpriteEffects.None;
			else if ( Velocity.X < 0.0f )
				m_sprite.Effect = SpriteEffects.FlipHorizontally;

			if ( !dontDoGround )
			{
				OnGround = false;
				if ( Position.Y >= groundHeight )
				{
					Position.Y = groundHeight;
					Velocity.Y = 0.0f;

					if ( Jumping )
						LandSfx.Play( );

					OnGround = true;

					Jumping = false;
				}
			}

			if ( Jumping || Sliding )
			{
			}
			else if ( OnGround )
			{
				if ( Math.Abs( Velocity.X ) > 0.0f )
				{
					if ( CurrentAnim == null || !( CurrentAnim is WalkAnim ) )
					{
						CurrentAnim = new WalkAnim( 1.0f, true );
					}
				}
				else
				{
					CurrentAnim = null;
				}
			}

			if ( CurrentAnim != null )
				CurrentAnim.Update( dt, this );
		}

		public void Render( SpriteBatch batch )
		{
			if ( CurrentAnim == null )
				m_sprite.Render( batch, Position, Rotation );
			else
				m_sprite.Render( batch, CurrentAnim.GetPos( this ), Rotation + CurrentAnim.GetRotation( this ) );
		}
	}

	public interface ICharAnim
	{
		void Update( float dt, Character c );

		Vector2 GetPos( Character c );

		float GetRotation( Character c );
	}

	public class WalkAnim : ICharAnim
	{
		private float sinWave = 0.0f;

		private float yPosOffset = 0.0f;

		private float rot = 0.0f;

		private float Val;

		private bool canPlaySfx = true;

		private bool PlaySound = false;

		public WalkAnim( float val, bool playsound )
		{
			Val = val;
			PlaySound = playsound;
		}

		public void Update( float dt, Character c )
		{
			float sinVal = (float)Math.Sin( sinWave );

			if ( !c.Dead && PlaySound )
			{
				if ( Math.Abs( sinVal ) > 0.95f )
				{
					if ( canPlaySfx )
					{
						canPlaySfx = false;
						c.FootstepSfx.Play( );
					}
				}
				else
				{
					canPlaySfx = true;
				}
			}

			rot = sinVal * 0.25f * Val;

			sinVal += 1.0f;
			sinVal *= 0.5f;
			sinWave += dt * 20.0f;

			yPosOffset = sinVal * 8.0f;
		}

		public Vector2 GetPos( Character c )
		{
			Vector2 p = c.Position;
			p.Y -= yPosOffset;
			return p;
		}

		public float GetRotation( Character c )
		{
			return rot;
		}
	}

	public class JumpAnim : ICharAnim
	{
		private float timer = 0.0f;
		private float dir = 1.0f;

		public JumpAnim( )
		{
			if ( new Random( ).Next( 100 ) < 50 )
				dir = -1.0f;
		}

		public void Update( float dt, Character c )
		{
			timer += dt;
		}

		public Vector2 GetPos( Character c )
		{
			return c.Position;
		}

		public float GetRotation( Character c )
		{
			float ang = MathHelper.Clamp( timer, 0.0f, 0.5f );
			ang /= 0.5f;
			ang *= (float)Math.PI * 2.0f;
			ang *= dir;

			return ang;
		}
	}

	public class Slideanim : ICharAnim
	{
		private float dir = 1.0f;

		public Slideanim( )
		{
			if ( new Random( ).Next( 100 ) < 50 )
				dir = -1.0f;
		}

		public void Update( float dt, Character c )
		{
		}

		public Vector2 GetPos( Character c )
		{
			Vector2 p = c.Position;
			p.Y += c.m_sprite.origin.X;
			return p;
		}

		public float GetRotation( Character c )
		{
			return (float)-Math.PI * 0.5f * dir;
		}
	}

	public class SkydiveDeadAnim : ICharAnim
	{
		private float rot = 0.0f;

		public void Update( float dt, Character c )
		{
			rot += dt * 5.0f;
		}

		public Vector2 GetPos( Character c )
		{
			return c.Position;
		}

		public float GetRotation( Character c )
		{
			return rot;
		}
	}
}